Skip to content

Show warning when VCS integration is not authorized for auto-deployments#2887

Merged
hmacr merged 11 commits intomainfrom
ser-1129
Mar 16, 2026
Merged

Show warning when VCS integration is not authorized for auto-deployments#2887
hmacr merged 11 commits intomainfrom
ser-1129

Conversation

@hmacr
Copy link
Member

@hmacr hmacr commented Feb 26, 2026

Towards SER-1129

Screenshot 2026-03-16 at 1 00 34 PM

Summary by CodeRabbit

  • New Features

    • VCS deployment status is fetched on load with a loading placeholder.
  • Improvements

    • Unauthorized VCS deployments display a clear warning and guidance to resolve access.
    • Site and function views now show richer context (site, region, project) for clearer management.
  • Chores

    • Internal components updated to accept additional context for consistent behavior across pages.

@appwrite
Copy link

appwrite bot commented Feb 26, 2026

Console (appwrite/console)

Project ID: 688b7bf400350cbd60e9

Sites (1)
Site Status Logs Preview QR
 console-stage
688b7cf6003b1842c9dc
Ready Ready View Logs Preview URL QR Code

Tip

HTTPS and SSL certificates are handled automatically for all your Sites

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds VCS repository loading and authorization checks to src/lib/components/git/deploymentSource.svelte: new optional props resource, region, and project; on-mount async fetch via sdk.forProject(region, project).vcs.getRepository(resource.installationId, resource.providerRepositoryId) to set repository and authorized state; shows a Skeleton while loading and renders an Exclamation button with tooltip and link when unauthorized. Updates call sites: siteCard.svelte gains an optional site prop and passes resource={site}, region, and project into DeploymentSource; deploymentCard.svelte passes resource={$func}, region, and project; the page passes site={data.site} into SiteCard.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature being added: showing a warning when VCS integration is not authorized for auto-deployments, which aligns with the implementation in deploymentSource.svelte.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ser-1129
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can generate a title for your PR based on the changes.

Add @coderabbitai placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the reviews.auto_title_placeholder setting.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 26, 2026

Greptile Summary

Added VCS authorization checking for deployments to warn users when their repository integration isn't authorized for auto-deployments. The warning appears as an icon next to the GitHub source link with a tooltip explaining how to fix it.

Key changes:

  • DeploymentSource component now accepts optional resource, region, and project props to fetch authorization status
  • Authorization is checked async on mount via VCS API
  • Warning icon displays when authorized === false
  • DeploymentCard and SiteCard updated to pass required props

Critical issue:

  • SiteCard component now requires a site prop, but two existing pages weren't updated and will break at runtime

Confidence Score: 2/5

  • This PR introduces a breaking change that will cause runtime errors on two pages
  • The site prop was made required in SiteCard but two existing pages (deployment-[deployment]/+page.svelte and create-site/finish/+page.svelte) were not updated to pass this prop, which will cause runtime errors
  • siteCard.svelte requires immediate attention - the site prop should either be made optional or all call sites must be updated

Important Files Changed

Filename Overview
src/lib/components/git/deploymentSource.svelte Added authorization check for VCS deployments with warning indicator; requires new optional props (resource, region, project)
src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte Added required site prop and passes it to DeploymentSource; breaks two existing pages that call this component

Sequence Diagram

sequenceDiagram
    participant Page as Site/Function Page
    participant Card as DeploymentCard/SiteCard
    participant DS as DeploymentSource
    participant API as VCS API
    
    Page->>Card: Pass deployment + resource + region + project
    Card->>DS: Pass all props
    Note over DS: onMount()
    DS->>DS: Check if resource has installationId & providerRepositoryId
    alt Has required data
        DS->>API: getRepository(installationId, providerRepositoryId)
        API-->>DS: { authorized: boolean }
        DS->>DS: Set authorized state
        alt authorized === false
            DS->>DS: Render warning icon with tooltip
        end
    else Missing data
        DS->>DS: authorized stays null (no warning shown)
    end
Loading

Last reviewed commit: ba7e9ce

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/routes/(console)/project-[region]-[project]/sites/site-[site]/+page.ts (1)

103-110: Avoid swallowing all fetch errors silently.

At Line 108 and Line 129, returning null for every exception hides operational failures. Consider at least logging unexpected errors so production issues remain debuggable.

Suggested pattern
 async function loadDeployment({
@@
 }): Promise<Models.Deployment | null> {
     try {
         return await sdk.forProject(region, project).sites.getDeployment({
             siteId,
             deploymentId
         });
     } catch (error) {
+        console.error('Failed to load site deployment', { siteId, deploymentId, error });
         return null;
     }
 }
@@
 }): Promise<Models.ProviderRepository | null> {
     try {
         return await sdk.forProject(region, project).vcs.getRepository({
             installationId,
             providerRepositoryId
         });
     } catch (error) {
+        console.error('Failed to load site repository', {
+            installationId,
+            providerRepositoryId,
+            error
+        });
         return null;
     }
 }

Also applies to: 124-131

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(console)/project-[region]-[project]/sites/site-[site]/+page.ts
around lines 103 - 110, The catch block that wraps
sdk.forProject(...).sites.getDeployment currently swallows all errors and
returns null; change it to detect and handle expected "not found" responses
(e.g., check error.status === 404 or SDK-specific NotFound error) returning null
only in that case, but for all other exceptions log the error with context
(include region, project, siteId, deploymentId) using the project's logger (or
console.error if no logger available) and rethrow or return a meaningful error;
update the catch around sdk.forProject(...).sites.getDeployment (and the similar
block calling the same method) accordingly so operational failures are not
silently hidden.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/routes/`(console)/project-[region]-[project]/functions/function-[function]/+page.ts:
- Around line 69-70: The load function currently mutates the module-scoped
queries store by calling queries.set(parsedQueries) after computing
parsedQueries with queryParamToMap(query || '[]'); remove that mutation from the
load function and instead return parsedQueries as part of the load data payload
(e.g., return { parsedQueries }). Then initialize the queries store on the
client: subscribe/ set it inside a client-only context such as a +page.svelte
onMount or a script tag with context="module" avoided—use onMount to call
queries.set(data.parsedQueries) or otherwise subscribe to load data; update the
+page.svelte to read the returned parsedQueries and set the queries store there
so SSR does not mutate shared module state.

In
`@src/routes/`(console)/project-[region]-[project]/sites/site-[site]/+page.svelte:
- Around line 39-44: Replace the generic link text "here" in the Link component
with descriptive copy that conveys the destination (e.g., "Manage GitHub App
installation" or "View GitHub installation settings") and update the Link
(component named Link, href constructed with
data.repository.providerInstallationId) to include an accessible label if
additional context is needed (aria-label) so screen readers see the destination
out of context; ensure the text mentions GitHub and installation/settings to
match the URL.

---

Nitpick comments:
In `@src/routes/`(console)/project-[region]-[project]/sites/site-[site]/+page.ts:
- Around line 103-110: The catch block that wraps
sdk.forProject(...).sites.getDeployment currently swallows all errors and
returns null; change it to detect and handle expected "not found" responses
(e.g., check error.status === 404 or SDK-specific NotFound error) returning null
only in that case, but for all other exceptions log the error with context
(include region, project, siteId, deploymentId) using the project's logger (or
console.error if no logger available) and rethrow or return a meaningful error;
update the catch around sdk.forProject(...).sites.getDeployment (and the similar
block calling the same method) accordingly so operational failures are not
silently hidden.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6965800 and 1e3b03a.

📒 Files selected for processing (4)
  • src/routes/(console)/project-[region]-[project]/functions/function-[function]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/functions/function-[function]/+page.ts
  • src/routes/(console)/project-[region]-[project]/sites/site-[site]/+page.svelte
  • src/routes/(console)/project-[region]-[project]/sites/site-[site]/+page.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/lib/components/git/deploymentSource.svelte (1)

29-41: Optional: Add explicit type to authorized for consistency.

TypeScript strict null checks are currently disabled in this project, so the current declaration works without issues. However, for consistency with similar state declarations elsewhere (e.g., multiSelectTable.svelte), consider explicitly typing the state:

♻️ Proposed fix
-    let authorized = $state(null);
+    let authorized = $state<boolean | null>(null);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/components/git/deploymentSource.svelte` around lines 29 - 41, The
local state variable authorized is declared without an explicit type; update the
declaration of authorized to include an explicit type (matching other components
like multiSelectTable.svelte) such as boolean | null (or the specific
Writable/State type you use) so its intended shape is clear and consistent,
leaving the existing initializer ($state(null)) and keeping loadAuthorized and
its assignment (authorized = repository.authorized) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/components/git/deploymentSource.svelte`:
- Around line 29-41: The local state variable authorized is declared without an
explicit type; update the declaration of authorized to include an explicit type
(matching other components like multiSelectTable.svelte) such as boolean | null
(or the specific Writable/State type you use) so its intended shape is clear and
consistent, leaving the existing initializer ($state(null)) and keeping
loadAuthorized and its assignment (authorized = repository.authorized)
unchanged.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e3b03a and de1ef99.

📒 Files selected for processing (4)
  • src/lib/components/git/deploymentSource.svelte
  • src/routes/(console)/project-[region]-[project]/functions/function-[function]/(components)/deploymentCard.svelte
  • src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte
  • src/routes/(console)/project-[region]-[project]/sites/site-[site]/+page.svelte

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/components/git/deploymentSource.svelte`:
- Around line 30-44: The template is calling loadAuthorized() inside a {`#await`
...} which recreates the Promise on every render; move the auth check out of the
template and invoke loadAuthorized imperatively only when inputs change (e.g.,
in an onMount and/or a reactive statement that watches resource.installationId,
resource.providerRepositoryId, region, and project) so it only calls
sdk.forProject(...).vcs.getRepository once per actual dependency change; keep
the function loadAuthorized and its try/catch as-is but stop calling it from the
template and ensure authorized is updated only by that controlled invocation.

In
`@src/routes/`(console)/project-[region]-[project]/sites/(components)/siteCard.svelte:
- Around line 32-39: The SiteCard currently declares the prop "site" as optional
but the VCS warning (which relies on DeploymentSource needing
resource.installationId and resource.providerRepositoryId) requires those
identifiers; either make "site" required by changing the prop type from site?:
Models.Site to site: Models.Site in SiteCard (and also update the other prop
declaration block around lines 213-217) and update the two callers in
sites/site-[site]/deployments/.../+page.svelte and
sites/create-site/finish/+page.svelte to pass the site object, OR implement a
fallback inside SiteCard to compute installationId/providerRepositoryId from
other available data (e.g., deployment.resource or proxyRuleList) and use that
when site is undefined; reference the prop declaration in siteCard.svelte and
ensure all callsites that previously omitted site are updated if you choose the
required-route.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 194dfd33-46f9-476c-9fb4-547ded63a6c6

📥 Commits

Reviewing files that changed from the base of the PR and between a95a9c3 and 0353c0b.

📒 Files selected for processing (2)
  • src/lib/components/git/deploymentSource.svelte
  • src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/lib/components/git/deploymentSource.svelte (1)

57-93: ⚠️ Potential issue | 🟠 Major

Calling loadRepository() in {#await} triggers duplicate API requests.

This issue was previously flagged: calling an async function directly inside {#await loadRepository()} creates a new Promise on every invalidation. When repository state updates on line 44, it triggers a re-render, which re-evaluates the await expression and makes another API call.

Use a $effect() to fetch once when dependencies change, and track loading state separately:

♻️ Suggested fix
 let repository = $state<Models.ProviderRepository | null>(null);
+let loading = $state(false);

-async function loadRepository() {
-    if (!resource?.installationId || !resource?.providerRepositoryId || !region || !project) {
-        return;
-    }
-
-    try {
-        repository = await sdk.forProject(region, project).vcs.getRepository({
-            installationId: resource.installationId,
-            providerRepositoryId: resource.providerRepositoryId
-        });
-    } catch (err) {
-        console.warn(err);
-    }
-}
+$effect(() => {
+    if (!resource?.installationId || !resource?.providerRepositoryId || !region || !project) {
+        return;
+    }
+
+    loading = true;
+    sdk.forProject(region, project)
+        .vcs.getRepository({
+            installationId: resource.installationId,
+            providerRepositoryId: resource.providerRepositoryId
+        })
+        .then((repo) => {
+            repository = repo;
+        })
+        .catch((err) => {
+            console.warn(err);
+        })
+        .finally(() => {
+            loading = false;
+        });
+});

Then in the template:

-{`#await` loadRepository()}
+{`#if` loading}
     <Layout.Stack direction="row" gap="xs" alignItems="center">
         <Skeleton variant="line" width={100} height={20} />
     </Layout.Stack>
-{:then}
+{:else}
     <Layout.Stack direction="row" gap="xs" alignItems="center">
         ...
     </Layout.Stack>
-{/await}
+{/if}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/components/git/deploymentSource.svelte` around lines 57 - 93, The
template is calling loadRepository() directly inside the {`#await`} block which
recreates a new Promise on every re-render (e.g., when repository changes) and
triggers duplicate API requests; instead, call loadRepository once from a
reactive/effect or onMount and store its result in a stable variable (e.g.,
repositoryPromise or set repository + loading flags) and then use that stable
variable in the template's {`#await` repositoryPromise} (or check
loading/repository for conditional rendering). Update the code to stop invoking
loadRepository() in the await expression, move the call into a $effect() or
onMount to re-run only when intended dependencies change, and ensure repository
and loading state are updated by the loadRepository handler so the UI uses those
values rather than re-creating the Promise.
🧹 Nitpick comments (1)
src/lib/components/git/deploymentSource.svelte (1)

73-90: Consider using Tooltip instead of nested Popover for hover-based warning.

The nested Popover requires a click to show the warning. If the intent is to show the warning on hover (as the PR screenshot suggests), consider using a Tooltip component instead, which would provide a more discoverable UX for the authorization warning.

However, if click-to-reveal is the desired interaction, this implementation is fine.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/components/git/deploymentSource.svelte` around lines 73 - 90, The
current implementation uses a click-activated Popover (Popover with let:toggle
and Button on:click={toggle}) to show the authorization warning, but the
reviewer suggests a hover-based Tooltip for better discoverability; replace the
Popover/ Button/ svelte:fragment tooltip block with the project's Tooltip
component (rendering the same Typography.Text and Link content) so the message
appears on hover, or if click behavior is intended, keep Popover but make that
explicit in the UI/props; locate the block using Popover, Button, toggle,
IconExclamation, and repository.providerInstallationId to apply the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/lib/components/git/deploymentSource.svelte`:
- Around line 57-93: The template is calling loadRepository() directly inside
the {`#await`} block which recreates a new Promise on every re-render (e.g., when
repository changes) and triggers duplicate API requests; instead, call
loadRepository once from a reactive/effect or onMount and store its result in a
stable variable (e.g., repositoryPromise or set repository + loading flags) and
then use that stable variable in the template's {`#await` repositoryPromise} (or
check loading/repository for conditional rendering). Update the code to stop
invoking loadRepository() in the await expression, move the call into a
$effect() or onMount to re-run only when intended dependencies change, and
ensure repository and loading state are updated by the loadRepository handler so
the UI uses those values rather than re-creating the Promise.

---

Nitpick comments:
In `@src/lib/components/git/deploymentSource.svelte`:
- Around line 73-90: The current implementation uses a click-activated Popover
(Popover with let:toggle and Button on:click={toggle}) to show the authorization
warning, but the reviewer suggests a hover-based Tooltip for better
discoverability; replace the Popover/ Button/ svelte:fragment tooltip block with
the project's Tooltip component (rendering the same Typography.Text and Link
content) so the message appears on hover, or if click behavior is intended, keep
Popover but make that explicit in the UI/props; locate the block using Popover,
Button, toggle, IconExclamation, and repository.providerInstallationId to apply
the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ebfa473e-627f-4e57-8b66-02ba973a6130

📥 Commits

Reviewing files that changed from the base of the PR and between 0353c0b and c0fa6ce.

📒 Files selected for processing (1)
  • src/lib/components/git/deploymentSource.svelte

@hmacr hmacr merged commit adf369e into main Mar 16, 2026
4 checks passed
@hmacr hmacr deleted the ser-1129 branch March 16, 2026 10:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants